/**
 * 
 */
package comunicaciones;

/**
 * @author hvc
 *
 */
import java.net.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.io.*;

import eventos.MensajeEventListener;
import automatas.AutomataEsclavo;

public class BuzonEsclavo extends Buzon implements IBuzon{
	
	private ConcurrentLinkedQueue<Mensaje> escritura;
	private ConcurrentLinkedQueue<Mensaje> lectura;
	private BuzonLectura b_lectura;
	private BuzonEscritura b_escritura;
	
	private String host;
	private int puerto;
	
	//private volatile boolean inicializado;

	public BuzonEsclavo(AutomataEsclavo automata, String host, int puerto) {
		this.host = host;
		this.puerto = puerto;
		automata.establecerBuzon(this);
		//System.out.println("host:"+host+", puerto:"+puerto);
		this.escritura = new ConcurrentLinkedQueue<Mensaje>();
		this.lectura = new ConcurrentLinkedQueue<Mensaje>();
		//this.inicializado=false;
	}

	/* (non-Javadoc)
	 * @see java.lang.Thread#run()
	 */
	@Override
	public void run() {
		// TODO Auto-generated method stub
		Socket socket = null;
		/*
		System.out.println("Inicion de buzones esclavos y esperamos 15 segundos.");		
		try{
			Thread.sleep(10000);
		}catch(InterruptedException e){
			
		}
		*/
		for(int i = 0; i < 2; i++){
			try{
				socket = new Socket(host, puerto);
			}catch(java.net.UnknownHostException e1){
				System.out.println("La direccion IP del host no ha podido ser determinada.");
				//socketS.close();
	        	e1.printStackTrace();
				System.exit(1);
			}catch(IOException e2){
				System.out.println("Un error de E/S ha ocurrido cuando se creaba el socket.");
				//socketS.close();
	        	e2.printStackTrace();
				System.exit(1);
			}catch(SecurityException e3){
				System.out.println("Existe un manejador de seguridad y su metodo \"checkConnect\" no permite la operacion.");
				//socketS.close();
	        	e3.printStackTrace();
				System.exit(1);
			}
			//System.out.println ("Conectado con el servidor.");
			if(socket!=null){
				if(i == 0){
					b_lectura = new BuzonLectura(socket, this);
					b_lectura.start();
					System.out.println("Buzon Esclavo lectura iniciado.");
				}else{
					this.b_escritura = new BuzonEscritura(socket,this);
					b_escritura.start();
					System.out.println("Buzon Esclavo escritura iniciado.");
				}
			}else
				i = -1;
		}
		//this.setInicializado(true);
		synchronized(this){
			if(this.b_lectura!=null){
				notifyAll();
				System.out.println("Despertamos");
			}
		}
		try{
			this.join();
			System.out.println("join en el buzon esclavo");
		}catch(InterruptedException e){
			System.out.println("Error en el join.");
			//socket.close();
        	e.printStackTrace();
			System.exit(1);
		}
	}

	/* (non-Javadoc)
	 * @see comunicaciones.Buzon#escribir(comunicaciones.Mensaje)
	 */
	
	public boolean escribir(Mensaje mensaje) {
		// TODO Auto-generated method stub
		return addMenssageEscritura(mensaje);
	}

	/* (non-Javadoc)
	 * @see comunicaciones.Buzon#leer()
	 */
	
	public Mensaje leer() {
		// TODO Auto-generated method stub
		return obtenerMensajeLectura();
	}

	/* (non-Javadoc)
	 * @see comunicaciones.Buzon#addMenssageEscritura(java.lang.Integer)
	 */
	@Override
	public synchronized boolean addMenssageEscritura(Mensaje i) {
		// TODO Auto-generated method stub
		boolean res = this.escritura.offer(i);
		if(!res)
			System.out.println("Error al aniadir un mensaje de escritura");
		return res;
	}

	/* (non-Javadoc)
	 * @see comunicaciones.Buzon#addMenssageLectura(java.lang.Integer)
	 */
	@Override
	public synchronized void addMenssageLectura(Mensaje i) {
		// TODO Auto-generated method stub
		boolean res = this.lectura.offer(i);
		if(!res)
			System.out.println("Error al aniadir un mensaje de lectura");
	}

	/* (non-Javadoc)
	 * @see comunicaciones.Buzon#hayMensajesEscritura()
	 */
	@Override
	protected boolean hayMensajesEscritura() {
		// TODO Auto-generated method stub
		if(escritura.isEmpty())
			return false;
		else
			return true;
	}

	/* (non-Javadoc)
	 * @see comunicaciones.Buzon#hayMensajesLectura()
	 */
	@Override
	protected boolean hayMensajesLectura() {
		// TODO Auto-generated method stub
		if(lectura.isEmpty())
			return false;
		else
			return true;
	}

	/* (non-Javadoc)
	 * @see comunicaciones.Buzon#obtenerMensajeEscrituta()
	 */
	@Override
	protected synchronized Mensaje obtenerMensajeEscrituta() {
		// TODO Auto-generated method stub
		return escritura.poll();
	}

	/* (non-Javadoc)
	 * @see comunicaciones.Buzon#obtenerMensajeLectura()
	 */
	@Override
	protected synchronized Mensaje obtenerMensajeLectura() {
		// TODO Auto-generated method stub
		return lectura.poll();
	}

	/**
	 * @return the escritura
	 */
	public ConcurrentLinkedQueue<Mensaje> getEscritura() {
		return escritura;
	}

	/**
	 * @param escritura the escritura to set
	 */
	public void setEscritura(ConcurrentLinkedQueue<Mensaje> escritura) {
		this.escritura = escritura;
	}

	/**
	 * @return the lectura
	 */
	public ConcurrentLinkedQueue<Mensaje> getLectura() {
		return lectura;
	}

	/**
	 * @param lectura the lectura to set
	 */
	public void setLectura(ConcurrentLinkedQueue<Mensaje> lectura) {
		this.lectura = lectura;
	}
	
	public void cerrar(boolean caida){
		System.out.println("Cerrado el buzon Esclavo.");
		this.b_escritura.cerrar();
		this.b_lectura.cerrar();
	}	
	
	public synchronized void addMensajeEventListener(MensajeEventListener listener){
		try{
			while (this.b_lectura==null)
				//System.out.println("B_LECTURA NULL");
				wait();
				//System.out.println("B_LECTURA OK");
				this.b_lectura.addMensajeEventListener(listener);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void removeMensajeEventListener(MensajeEventListener listener){
		this.b_lectura.removeMensajeEventListener(listener);
	}
	
	public int getListener(){
		if(this.b_lectura == null){
			System.out.println("B LECTURA NULL");
			return -1;
		}else{
			return this.b_lectura.getListaListeners().getListenerCount();
		}
	}
}
